﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Manzana;
using System.Diagnostics;
using System.ComponentModel;
using System.IO;
using System.Threading;

namespace IVR3Downloader.Class
{
    internal class IVR3
    {
        private static readonly string JB_PATH = @"/private/var/mobile/Media/iPhoneVideoRecorder";
        private static readonly string NO_JB_PATH = @"/iPhoneVideoRecorder";

        private static IVR3 __ivr3iPhone = null;

        private iPhone _iPhone = null;
        private BackgroundWorker _backgroundWorker = null;
        private String _baseIVRPath = string.Empty;

        private bool _isConnected = false;

        public static event Connect OnConnect = null;
        public delegate void Connect();

        public static event Disconnect OnDisconnect = null;
        public delegate void Disconnect();

        private IVR3()
        {
            this._iPhone = new iPhone(iPhone_Connect, iPhone_Disconnect);
            //this._iPhone.ReConnect();
            
            //String d = this._iPhone.DeviceName;
          

        }

        #region Properties
        public BackgroundWorker BackgroundWorker
        {
            set
            {
                this._backgroundWorker = value;
            }
        }

        /// <summary>
        /// iPhone is connected ?
        /// True: yes, False no.
        /// </summary>
        public bool IsConnected
        {
            get
            {
                return this._isConnected;
            }
        }

        #endregion

        #region Methods
        public Movie[] ListVideos()
        {
            Movie movie = null;
            List<Movie> movies = new List<Movie>();
            String[] files = null, moviesFile = null; 

            if (this._iPhone.IsJailbreak)
            {
                this._baseIVRPath = JB_PATH;
            }
            else
            {
                this._baseIVRPath = NO_JB_PATH;
            }

            files = this._iPhone.GetFiles(this._baseIVRPath);

            //Select only file with extension .mov or .mp4
            moviesFile = files.Where(f => Path.GetExtension(f).Equals(".mov") || Path.GetExtension(f).Equals(".mp4")).ToArray();
            //moviesFile = files.ToArray();

            foreach (String file in moviesFile)
            {
                String fullPathFile = String.Format("{0}/{1}",this._baseIVRPath,file);
                ulong fileSize = this._iPhone.FileSize(fullPathFile);

                movie = new Movie()
                {
                    FilePath = fullPathFile,
                    FileSize = fileSize
                };

                movies.Add(movie);
                
            }

            return movies.ToArray();
        }

        public void Copy(Movie[] aMoviesToCopy, String aDestinationPath)
        {
            int fileCounter = 0;

            ProgressionFile p = new ProgressionFile()
            {
                FileTotal = aMoviesToCopy.Length,
            };

            this._backgroundWorker.ReportProgress(0, p);

            foreach (Movie m in aMoviesToCopy)
            {
                //Check if user cancel.
                if (this._backgroundWorker.CancellationPending)
                {
                    break;
                }

                this.Copy(m, aDestinationPath);
     
                fileCounter++;

                //Report file downloaded.
                p = new ProgressionFile()
                {
                   FileTotal = aMoviesToCopy.Length,
                   FileDone = fileCounter
                };
                this._backgroundWorker.ReportProgress(0, p);
            }//foreach
        }

        private void Copy(Movie aMovie, String aDestinationPath)
        {
            byte[] buffer = new byte[16000];
            ulong copyByte = 0;
            int nbByteRead = 0;
            copyByte = 0;
            ProgressionDownload p;

            String destinationFilePath = Path.Combine(aDestinationPath, aMovie.FileName);
            
            using (iPhoneFile f = iPhoneFile.OpenRead(this._iPhone, aMovie.FilePath))
            {
                using (BinaryWriter binWriter = new BinaryWriter(File.Open(destinationFilePath, FileMode.Create)))
                {
                    do
                    {
                        try
                        {
                            //Check if user cancel.
                            if (this._backgroundWorker.CancellationPending)
                            {
                                break;
                            }

                            nbByteRead = f.Read(buffer, 0, buffer.Length);

                            if (nbByteRead == 0)
                            {
                                break;
                            }
                            copyByte += (ulong)nbByteRead;
                            binWriter.Write(buffer, 0, nbByteRead);


                            p = new ProgressionDownload()
                            {
                                FileSize = aMovie.FileSize,
                                FileSizeDownloaded = copyByte
                            };

                            this._backgroundWorker.ReportProgress(0, p);
                        }
                        catch (IOException ioEx)
                        {
                            if (ioEx.Message.Contains("AFCFileRefRead error = 11"))
                            {
                                p = new ProgressionDownload()
                                {
                                    DownloadError = String.Format("Aborting ! Error downloading the file: " + aMovie.FileName + " ! Connection to device lost")
                                };
                                this._backgroundWorker.ReportProgress(0, p);

                                binWriter.Close();
                                try
                                {
                                    File.Delete(destinationFilePath);
                                }
                                catch (Exception) { }
                            }
                            

                            Debug.WriteLine("Download failed:" + ioEx);
                            break;
                        }
                    } while (true);

                }//using BinaryWriter
            }//using iPhoneFile

            //Final report progression.
            p = new ProgressionDownload()
            {
                FileSize = aMovie.FileSize,
                FileSizeDownloaded = copyByte
            };
            this._backgroundWorker.ReportProgress(0, p);
        }

        #endregion


        #region Events
        private void iPhone_Disconnect(object sender, ConnectEventArgs args)
        {
            this._isConnected = false;
            Debug.WriteLine("iPhone Disconnected");
            if (IVR3.OnDisconnect != null)
            {
                IVR3.OnDisconnect();
            }
        }

        private void iPhone_Connect(object sender, ConnectEventArgs args)
        {
            this._isConnected = true;

            Debug.WriteLine("iPhone Connected");
            if (IVR3.OnConnect != null)
            {
                IVR3.OnConnect();
            }
        }
        #endregion



        #region Static
        /// <summary>
        /// Get singleton instance.
        /// </summary>
        public static IVR3 Instance
        {
            get
            {
                if (IVR3.__ivr3iPhone == null)
                {
                    IVR3.__ivr3iPhone = new IVR3();
                }

                return IVR3.__ivr3iPhone;
            }
        }
        #endregion
    }
}
